package nameless.aistudy.global.filter;

import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import nameless.aistudy.common.constant.path.PublicPathConstants;
import nameless.aistudy.common.enumeration.user.RoleEnum;
import nameless.aistudy.common.result.Result;
import nameless.aistudy.common.util.jwt.JwtUtil;
import nameless.aistudy.domain.model.user.User;
import nameless.aistudy.domain.model.user.UserRepo;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

import static nameless.aistudy.common.constant.path.DispatchPathConstants.AUTH_FORBIDDEN_PATH;
import static nameless.aistudy.common.constant.path.DispatchPathConstants.AUTH_UNAUTHORIZED_PATH;
import static nameless.aistudy.common.constant.path.PublicPathConstants.PUBLIC_PATHS;

@Controller
public class JwtFilter extends OncePerRequestFilter {

    private final PublicPathConstants publicPathConstants;
    private final UserRepo userRepo;

    public JwtFilter(PublicPathConstants publicPathConstants, UserRepo userRepo) {
        this.publicPathConstants = publicPathConstants;
        this.userRepo = userRepo;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

        String path = request.getRequestURI();
        if (equalsOneOf(path, PUBLIC_PATHS) || startsWithOneOf(path, publicPathConstants.getPublicPrefixes())) {
            chain.doFilter(request, response);
            return;
        }

        String authHeader = request.getHeader("Authorization");
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            sendUnauthorizedMessage(request, response, "未登录（缺少预期的Authorization响应头字段）");
            return;
        }

        String token = authHeader.substring(7);
        try {
            int userId = Integer.parseInt(JwtUtil.getUserIdFromToken(token));
            User user = userRepo.selectById(userId);
            int userRoleId = user.getRole();

            if (path.startsWith("/super-admin")) {
                if (userRoleId != RoleEnum.SUPER_ADMIN.getId()) {
                    sendForbiddenMessage(request, response, "需要超级管理员权限");
                    return;
                }
            }
            else if (path.startsWith("/admin")) {
                if (userRoleId == RoleEnum.USER.getId()) {
                    sendForbiddenMessage(request, response, "需要管理员权限");
                    return;
                }
            }

            request.setAttribute("userId", userId);

        } catch (ExpiredJwtException e) {
            sendUnauthorizedMessage(request, response, "登录状态过期");
            return;
        } catch (JwtException e) {
            sendUnauthorizedMessage(request, response, "未登录（Token无效）");
            return;
        } catch (Exception e) {
            sendUnauthorizedMessage(request, response, "Token无效：" + e.getMessage());
            return;
        }

        chain.doFilter(request, response);
    }

    private boolean equalsOneOf(String path, String... paths) {
        for (String p : paths) {
            if (path.equals(p)) {
                return true;
            }
        }
        return false;
    }

    private boolean startsWithOneOf(String path, String... prefixes) {
        for (String prefix : prefixes) {
            if (path.startsWith(prefix)) {
                return true;
            }
        }
        return false;
    }

    private void sendUnauthorizedMessage(HttpServletRequest request, HttpServletResponse response, String message) throws ServletException, IOException {
        request.setAttribute("message", message);
        request.getRequestDispatcher(AUTH_UNAUTHORIZED_PATH).forward(request, response);
    }

    private void sendForbiddenMessage(HttpServletRequest request, HttpServletResponse response, String message) throws ServletException, IOException {
        request.setAttribute("message", message);
        request.getRequestDispatcher(AUTH_FORBIDDEN_PATH).forward(request, response);
    }

}
